/*
* 需要以下
* 1.jQuery
* 2.layui 上传需要
* 3.dragula 拖动js(可选)
* 3.preview 大图预览(可选)
* */
;gallery = function (_options) {
    //defaultOptions
    let serialIndex = 0;
    let options = {
        id: new Date().getTime(),
        prefix: 'ln',
        fImages: [],//formatter data
        images: [],

        preview: true,
        delete: true,
        onDelete: undefined,
        onUploadHandle: onUploadHandle,

        number: 5,//同时可选中五个
        autoUpload: true,
        multiple: true,
        acceptMime: 'image/*', //只筛选图片  acceptMime: 'image/jpg, image/png'

        classes: {
            gallery: 'gallery',
            images: 'images',
            imagesItem: 'images-item',
            imagesImg: 'images-img',
            actions: 'actions',
            actionsItem: 'actions-item',
            actionsItemPreview: 'preview',
            actionsItemDelete: 'delete',
            upload: 'upload',
        }
    };

    $.extend(options, _options);
    //console.log('options', options, _options)

    let id = options.id;
    let $root = $(options.el);

    identityClass(options.classes, options.prefix);
    let galleryClass = options.classes.gallery,
        uploadClass = options.classes.upload,
        imagesClass = options.classes.images,
        imagesItemClass = options.classes.imagesItem,
        imagesImgClass = options.classes.imagesImg,
        actionsClass = options.classes.actions,
        actionsItemClass = options.classes.actionsItem,
        actionsItemPreviewClass = options.classes.actionsItemPreview,
        actionsItemDeleteClass = options.classes.actionsItemDelete,
        uploadElem = `.${uploadClass}`;

    let $wrapper = $(`<div class="${galleryClass}"></div>`);
    let $images = $(`<ul class="${imagesClass}"></ul>`);

    let $imageItemTemplate = $(`${getImageItemTemplateHtml()}`);
    let $upload = $(`<div class="${uploadClass}"> <i class="fa fa-upload fa-2x" aria-hidden="true"></i></div>`);

    function init() {
        if (isDefined(preview))
            preview.init();

        $root.append($wrapper);
        $wrapper.append($images);
        $wrapper.append($upload);
        renderAll(options.images);

        if (isDefined(dragula)) {
            let drake = dragula([$(`.${imagesClass}`).get(0)], {});
            drake.on('dragend', onDragEnd);
        }

        bindUpload();
        bindImageAction();
    }

    function onDragEnd(el) {
        //console.log('dragend', el, this)
        if (this.dragging) return;

        sort();
    }

    function sort() {
        let images = options.images || [];
        $(`.${galleryClass} .${imagesClass} .${imagesItemClass}`).each(function (index, el) {
            console.log('sort', index, el)
            let $item = $(this),
                id = $item.data('id');
            let image = ArrayGetItem(images, 'id', id);
            if (image) {
                image.sort = index;
            }
        });

        images.sort((a, b) => a.sort - b.sort)
    }

    function identityClass(classes, prefix) {
        for (let key in classes) {
            classes[key] = `${prefix}-` + classes[key];
        }
    }

    function bindImageAction() {
        let baseSelector = `.${galleryClass} .${imagesClass} .${imagesItemClass}`;

        $root.on('mousedown', `${baseSelector} .${actionsItemClass}`, e => {
            e.stopPropagation();
            e.cancelBubble = true;
        });

        if (options.preview)
            $root.on('click', `${baseSelector} .${actionsItemClass}.${actionsItemPreviewClass}`, bindImageActionPreview);

        if (options.delete)
            $root.on('click', `${baseSelector} .${actionsItemClass}.${actionsItemDeleteClass}`, bindImageActionDelete);
    }

    function bindImageActionPreview() {
        //console.log('bindImageActionPreview')
        let $this = $(this),
            $item = $this.parents(`.${imagesItemClass}`),
            url = $item.data('url');
        preview.show(url)
    }

    async function bindImageActionDelete() {
        let $this = $(this),
            $item = $this.parents(`.${imagesItemClass}`);
        //console.log('bindImageActionDelete', $this, $item)

        let images = options.images || [],
            id = $item.data('id'),
            image = ArrayGetItem(images, 'id', id);

        let confirmDelete = true;
        if (isFunction(options.onDelete))
            confirmDelete = await options.onDelete(image);

        if (confirmDelete) {
            ArrayRemoveItem(images, image);
            $item.remove();
        }
    }


    function isDefined(obj) {
        return typeof obj !== 'undefined';
    }

    function isFunction(fun) {
        return fun && (typeof fun).toLowerCase() === 'function';
    }

    /**
     * @return {String}
     */
    function ArrayGetItem(arr, key, keyValue) {
        if (!arr || !Array.isArray(arr)) return undefined;

        let filterData = arr.filter(item => item[key] === keyValue);

        return filterData.length > 0 ? filterData[0] : undefined;
    }

    function ArrayRemoveItem(arr, item) {
        if (!arr || !Array.isArray(arr)) return arr;

        let index = arr.indexOf(item);
        if (index === -1) return arr;

        arr.splice(index, 1);
        return arr;
    }

    function getImageItemTemplateHtml() {
        let imageItemActionPreview = ``;
        if (options.preview)
            imageItemActionPreview = `<span class="${actionsItemPreviewClass} ${actionsItemClass}"><i class="fa fa-search-plus" aria-hidden="true"></i></span>`;

        let imageItemActionDelete = ``;
        if (options.delete)
            imageItemActionDelete = `<span class="${actionsItemDeleteClass} ${actionsItemClass}"><i class="fa fa-trash" aria-hidden="true"></i></span>`;

        let imageItemActionHtml = `<span class="${actionsClass}">${imageItemActionPreview}${imageItemActionDelete}</span>`;
        return `<li class="${imagesItemClass}"><img class="${imagesImgClass}" > ${imageItemActionHtml}</li>`;
    }

    function renderAll(images) {
        images.sort((a, b) => a.sort - b.sort);

        $images.empty();
        images.map(renderAfter);
    }

    function renderAfter(image) {
        let $item = $imageItemTemplate.clone();
        $item.data('url', image.url).data('id', image.id);
        $item.find(`.${imagesImgClass}`).attr('src', image.url).attr('alt', image.id);
        $images.append($item)
    }

    function message(msg) {
        if (msg !== undefined)
            alert(msg);
        return false;
    }

    function onUploadSuccess(resp) {
        let handle = options.onUploadHandle;

        let image = handle(resp);
        if (!image) return;

        images.push(image);
        renderAfter(image)
    }

    function onUploadHandle(resp) {
        //resp
        if (!resp ||
            (resp.statu !== 1 && resp.code !== 200 && !resp.succeed)) {
            return message(resp.msg || resp.message || resp.Msg || `上传失败`)
        }

        let images = options.images || [];
        //数量限制
        if (images.length >= options.number) {
            return message(`最多选择${options.number}张图`)
        }

        //处理数据
        let data = resp.data || {};
        return {
            id: new Date().getTime() + '_' + serialIndex++,
            url: data.url,
            source: data,
            isNew: true
        };
    }

    function bindUpload() {
        if (!isDefined(layui))
            return;

        layui.use('upload', function () {
            var upload = layui.upload;

            //执行实例
            var uploadInst = upload.render({
                elem: uploadElem//绑定元素
                , url: options.url //上传接口
                , multiple: options.multiple
                , number: options.number //同时可选中五个
                , accept: 'images' //指定允许上传时校验的文件类型，可选值有：images（图片）、file（所有文件）、video（视频）、audio（音频）
                , auto: options.autoUpload
                , acceptMime: options.acceptMime //只筛选图片
                , choose: function (obj) {
                    //console.log('choose', obj);
                    //将每次选择的文件追加到文件队列
                    //var files = obj.pushFile();
                    //console.log('choose', files);

                }
                , allDone: function (obj) { //当文件全部被提交后，才触发
                    //console.log('allDone', obj); //得到总文件数
                }
                , done: function (resp) {
                    //上传完毕回调
                    console.log('done', resp);
                    onUploadSuccess(resp);
                }
                , error: function (resp, upload) {
                    //请求异常回调
                    console.log('error', resp, upload);
                }
            });
        });
    }

    return init;
};